(function ($, mini) {
    var minix = {
        version: '0.0.1',
        author: 'georgehu',
        git: 'https://git.oschina.net/georgehu/minix.git',
        debug: true,
        hasValue: function (obj) {
            if (typeof obj == undefined || obj == null) {
                return false;
            }

            return true;
        },

        assertNotNull: function (obj) {
            if (!$mx.hasValue(obj)) {
                var msg = 'obj is null';
                $mx.log.error(msg);
            }
        },

        assertAtLeastOneValue: function () {
            if (arguments.length == 0) {
                $mx.log.error("method should has at least one argument!");
            }

            var exitingValue = false;
            for (var i = 0; i < arguments.length; i++) {
                if ($mx.hasValue(arguments[i])) {
                    exitingValue = true;
                    break;
                }
            }

            if (!exitingValue) {
                $mx.log.error("at least one argument of this method should has value!");
            }
        },

        getParam: function (paraName) {
            var search = document.location.search,
                reg = new RegExp("[?&]+" + paraName + "=([^&]+)");
            if (search && reg.test(search)) {
                return decodeURIComponent(RegExp['$1']).replace(/\+/g, " ");
            }
            return null;
        },

        string: {
            trimRight: function (source, char) {
                return source.replace(new RegExp('\\' + char + '+$', 'g'), '');
            }
        },

        log: {
            info: function (message) {
                if ($mx.debug) {
                    console.log(message);
                }
            },
            error: function (msg) {
                throw new Error(msg);
            }
        },

        date: {
            format: function (pattern) {

            }
        },

        path: {
            isRelativePath: function (url) {
                var containsHttp = url.toLowerCase().indexOf("http://") > -1 || url.toLowerCase().indexOf("https://") > -1;
                return !containsHttp;
            },

            getSlashCount: function (relativeUrl) {
                var pos = -1;
                var count = 0;
                while (pos <= relativeUrl.length) {
                    pos = relativeUrl.indexOf('../', pos);
                    if (pos > -1) {
                        count++;
                        pos += '../'.length;
                    }
                    else {
                        break;
                    }
                }

                return count;
            },

            getAbsolutePath: function (relativeUrl) {
                if (relativeUrl.indexOf('../') == -1) {
                    return $mx.path.getPageRootUrl() + relativeUrl;
                }

                var fileName = relativeUrl.substring(relativeUrl.lastIndexOf('../') + 3);
                var slashes = $mx.path.getSlashCount(relativeUrl);
                var pageRootUrl = $mx.string.trimRight($mx.path.getPageRootUrl(), '/');
                var dirs = pageRootUrl.replace($mx.path.getWebsiteRootUrl(), "").split('/').reverse();
                for (var i = 0; i < slashes; i++) {
                    dirs.shift();
                }
                dirs.reverse();
                var absolutePath = $mx.path.getWebsiteRootUrl() + dirs.join("/") + '/' + fileName;
                return absolutePath;
            },

            getWebsiteRootUrl: function () {
                return window.location.origin + '/';
            },

            getPageRootUrl: function (pageUrl) {
                pageUrl = pageUrl || window.location.href;
                return pageUrl.substring(0, pageUrl.lastIndexOf('/') + 1);
            }
        },

        resourceLoader: {
            head: $(document.head),
            forceUpdate: false,
            loadedScripts: [],
            loadedCsses: [],
            detectLoadedResources: function () {
                var self = this;
                $("link[href]").each(function () {
                    var href = $(this).attr("href");
                    if ($mx.path.isRelativePath(href)) {
                        href = $mx.path.getAbsolutePath(href);
                    }
                    self.loadedCsses.push(href);
                });

                $("script[src]").each(function () {
                    var src = $(this).attr("src");
                    if ($mx.path.isRelativePath(src)) {
                        src = $mx.path.getAbsolutePath(src);
                    }
                    self.loadedScripts.push(src);
                });
            },

            loadPage: function (url, page, callback) {
                var self = this;
                self.head = page._jqHead;
                var requestAbsoluteUrl = url;
                if ($mx.path.isRelativePath(url)) {
                    requestAbsoluteUrl = $mx.path.getAbsolutePath(url);
                }

                $.ajax({
                    url: requestAbsoluteUrl,
                    type: 'get',
                    dataType: 'html',
                    success: function (data, status, xhr) {
                        var bodyHtml = self.parseBodyHtml(data);
                        callback.call(page, bodyHtml);
                        self.loadCsses(data);
                        self.loadScripts(data, page);
                    },
                    error: function () {
                        $mx.log.error(url + ' could not be loaded correctly!');
                    }
                });
            },

            loadScripts: function (rawHtml, page) {
                var self = this;
                var scriptPattern = /<script.*?src\s?=\s?"(.*?)"/g;
                var matchedScripts = scriptPattern.exec(rawHtml);
                var scripts = [];
                while (matchedScripts) {
                    scripts.push(matchedScripts[1]);
                    matchedScripts = scriptPattern.exec(rawHtml);
                }

                $(scripts).each(function () {
                    var scriptPath = this.valueOf();
                    if ($mx.path.isRelativePath(scriptPath)) {
                        scriptPath = $mx.path.getAbsolutePath(scriptPath);
                    }

                    if (!$mx.resourceLoader.loadedScripts.contains(scriptPath)) {
                        self.loadScript(scriptPath, page);
                    }
                });
            },

            loadCsses: function (rawHtml) {
                var self = this;
                var scriptPattern = /<link.*?href\s?=\s?"(.*?)"/g;
                var matchedLinks = scriptPattern.exec(rawHtml);
                var links = [];
                while (matchedLinks) {
                    links.push(matchedLinks[1]);
                    matchedLinks = scriptPattern.exec(rawHtml);
                }

                $(links).each(function () {
                    var cssPath = this.valueOf();
                    if ($mx.path.isRelativePath(cssPath)) {
                        cssPath = $mx.path.getAbsolutePath(cssPath);
                    }

                    if (!$mx.resourceLoader.loadedCsses.contains(cssPath)) {
                        self.loadCss(cssPath);
                    }
                });
            },

            loadScript: function (url, page) {
                var self = this;
                $.getScript(url, function (data, textStatus, jqxhr) {
                    self.loadedScripts.push(url);
                    $mx.log.info("load script: " + url);
                    self._runScript(data, page);
                });
            },

            loadCss: function (url) {
                var self = this;
                self.head = self.head || $(document.head);
                self.head.append("<link type=\"text/css\" href=\"" + url + "\" async=\"async\"></link>");
                self.loadedCsses.push(url);
                $mx.log.info("load css: " + url);
            },

            parseBodyHtml: function (rawHtml) {
                var bodyStartPos = rawHtml.indexOf("<body>");
                var bodyEndPos = rawHtml.indexOf("</body>");
                var bodyHtml = rawHtml.substring(bodyStartPos + 6, bodyEndPos);
                //var bodyHtml = data.match(/<body.*>(.|\n)*?<\/body>/gi);
                return bodyHtml;
            },

            _runScript: function (javascriptCode, page) {
                var fn = eval(javascriptCode);
                if ($.isFunction(fn)) {
                    var loadedPage = fn.call(window);
                    if (loadedPage && loadedPage instanceof $mx.page) {
                        loadedPage.parentPage = page;
                        loadedPage.hostContainer = page.id;
                        loadedPage._jqHostContainer = $("#" + page.id);
                        loadedPage._jqPageObj = loadedPage._jqHostContainer;
                        loadedPage._buildObjs(self._jqPageObj);
                        loadedPage.load();
                    }
                }
            }
        },

        idGenerator: {
            newId: function (prefix) {
                prefix = prefix || 'id';
                var id = new Date().getTime() + $mx._idRef++;
                return prefix + id;
            }
        },

        ajax: function (setting) {
            $.ajax(setting);
        },

        createPage: function (options) {
            return new minix.page(options);
        },

        findPageById: function (id) {
            return $mx.pages[id];
        },

        pages: [],
        _idRef: 1
    };

    minix.page = function (options) {
        var setting = {
            hostContainer: '',
            renderContent: '',
            renderMode: 'self',
            title: '',
            url: '',
            load: function () {
                $mx.log.info("page load");
            }
        };
        $.extend(setting, options);

        this.hostContainer = setting.hostContainer;
        this.renderContent = setting.renderContent;
        this.renderMode = setting.renderMode || 'self'; // iframe, div, self
        this.title = setting.title;
        this.url = setting.url;
        this.load = setting.load;

        this.jqObjs = [];
        this.miniObjs = [];
        this.id = $mx.idGenerator.newId('page');
        this.parentPage = null;
        $mx.pages.push(this);
        $mx.log.info("create page id=" + this.id);

        this._jqHead = $(document.head);
        this._jqPageObj = null;
        if ($mx.hasValue(options.renderContent)) {
            this._jqRenderContent = $("#" + this.renderContent);
        }
    };

    minix.page.prototype = {
        init: function () {
            var self = this;
            if (self.renderMode != 'self') {
                return;
            }

            self.hostContainer = "body";
            self._jqHostContainer = $("body");
            self._jqHostContainer.attr("id", self.id);
            self._jqPageObj = self._jqHostContainer;
            self._buildObjs(self._jqPageObj);
            self.load();
        },

        inject: function () {
            var self = this;
            $mx.assertNotNull(self.hostContainer);
            $mx.assertNotNull($("#" + self.hostContainer));
            self._jqHostContainer = $("#" + self.hostContainer);
            this._createPageDiv();
            $mx.log.info("page inject");

            if (self.renderMode == 'div') {
                if ($mx.hasValue(self.url)) {
                    $mx.resourceLoader.detectLoadedResources();
                    $mx.resourceLoader.loadPage(self.url, self, function (bodyHtml) {
                        self._jqRenderContent = null;
                        self.renderContent = bodyHtml;
                        self._injectDiv();
                    });
                    return;
                }

                if ($mx.hasValue(self.renderContent)) {
                    self._injectDiv();
                    return;
                }
            }

            if (self.renderMode == 'iframe') {
                self._injectIframe();
            }
        },

        popup: function (options) {
            var self = this;
            $mx.assertNotNull(self.renderMode);
            $mx.assertNotNull(self.url);
            $mx.log.info("page popup");
            var websiteRoot = $mx.path.getWebsiteRootUrl();
            if ($mx.path.isRelativePath(self.url)) {
                self.url = $mx.path.getAbsolutePath(self.url);
            }

            options = options || {};
            options.onLoad = options.onLoad || self.load;
            options.oneDestroy = options.oneDestroy || self.dispose;

            var setting = $.extend({
                url: self.url,
                title: self.title,
                width: window.screen.availWidth / 2,
                height: window.screen.availHeight / 2
            }, options);

            if (self.renderMode == 'div') {
                self.hostContainer = 'body';
                self._jqHostContainer = $(document.body);
                self._createPageDiv();

                if ($mx.hasValue(self.url)) {
                    $mx.resourceLoader.detectLoadedResources();
                    $mx.resourceLoader.loadPage(self.url, self, function (bodyHtml) {
                        self._jqPageObj.html(bodyHtml);
                        self._popupRenderContent(setting);
                    });
                    return;
                }

                if ($mx.hasValue(self.renderContent)) {
                    self.append(self._jqRenderContent);
                    self._popupRenderContent(setting);
                    return;
                }
            }

            if (self.renderMode == 'iframe') {
                self._popupIframeWin(setting);
            }
        },

        findMiniObjByUid: function (uid) {
            var self = this;
            var miniObjs = self.miniObjs || [];
            for (var i = 0; i < miniObjs.length; i++) {
                var obj = miniObjs[i];
                if (obj.uid == uid) {
                    return i;
                }
            }

            return -1;
        },

        dispose: function () {
            delete this.jqObjs;
            delete this.miniObjs;
        },

        _popupRenderContent: function (setting) {
            var self = this;
            self._jqPageObj.addClass("mini-window");
            self._jqPageObj.attr("title", setting.title);
            self._jqPageObj.css("width", window.screen.availWidth / 2);
            self._jqPageObj.css("height", window.screen.availHeight / 2);

            mini.parse();
            var win = mini.get(self.id);
            win.show();

            self.hostContainer = self.id;
            self._jqHostContainer = win;
            self._jqPageObj = $("#" + self.id);
            self._buildObjs(self._jqPageObj);
        },

        _popupIframeWin: function (setting) {
            $mx.log.info("mini open:" + setting.url);
            var self = this;
            var miniWin = mini.open(setting);
            self.miniObjs.push(miniWin);

            self.hostContainer = self.id;
            self._jqHostContainer = miniWin;
        },

        _createPageDiv: function () {
            var self = this;
            self._jqHostContainer.append("<div id='" + self.id + "'></div>");
            self._jqPageObj = $("#" + self.id);
        },

        _injectDiv: function () {
            var self = this;
            self._jqPageObj.empty();
            if (!$mx.hasValue(self._jqRenderContent)) {
                self._jqPageObj.append(self.renderContent);
                self._jqRenderContent = self._jqPageObj.first();
            }
            else {
                self._jqPageObj.append(self._jqRenderContent);
            }
            self._jqRenderContent.show();
            self._jqPageObj = $("#" + self.id);
            mini.parse();
            self._buildObjs(self._jqPageObj);
        },

        _injectIframe: function () {
            var self = this;
            self._jqPageObj.empty();
            mini.parse();
            self._jqPageObj.append("<iframe src='" + self.url + "' id='" + $mx.idGenerator.newId('page') + "' width='100%' height='100%'/>");
            self._jqPageObj = $("#" + self.id);
            self._buildObjs(self._jqPageObj);
        },

        _buildObjs: function (jqPageObj) {
            var self = this;
            self.jqObjs = jqPageObj.find("[id]");
            self.miniObjs = [];
            self.jqObjs.each(function () {
                var id = $(this).attr('id');
                var miniObj = mini.get(id);
                if ($mx.hasValue(miniObj)) {
                    self.miniObjs.push(mini.get(id));
                }
            });
        }
    };

    mini.parse();
    window.$mx = window.minix = minix;
})(jQuery, mini);